home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / swagd_f.zip / DOS.SWG / 0005_Edit DOS Environment.pas < prev    next >
Pascal/Delphi Source File  |  1993-05-28  |  14KB  |  583 lines

  1. {$R-,S-,V-,I-,B-,F-}
  2.  
  3. {Disable the following define if you don't have Turbo Professional}
  4. {$DEFINE UseTpro}
  5.  
  6. {*********************************************************}
  7. {*                    TPENV.PAS 1.02                     *}
  8. {*                by TurboPower Software                 *}
  9. {*********************************************************}
  10.  
  11. {
  12.   Version 1.01 11/7/88
  13.     Find master environment in Dos 3.3 and 4.0
  14.   Version 1.02 11/14/88
  15.     Correctly find master environment when run
  16.       Within AUTOEXEC.BAT
  17. }
  18.  
  19. Unit TpEnv;
  20.   {-Manipulate the environment}
  21.  
  22. Interface
  23.  
  24. Uses Opus;
  25.  
  26. Type
  27.   EnvArray = Array[0..32767] of Char;
  28.   EnvArrayPtr = ^EnvArray;
  29.   EnvRec =
  30.     Record
  31.       EnvSeg : Word;              {Segment of the environment}
  32.       EnvLen : Word;              {Usable length of the environment}
  33.       EnvPtr : Pointer;           {Nil except when allocated on heap}
  34.     end;
  35.  
  36. Const
  37.   ShellUserProc : Pointer = nil;  {Put address of ExecDos user proc here if desi
  38.  
  39. Procedure MasterEnv(Var Env : EnvRec);
  40.   {-Return master environment Record}
  41.  
  42. Procedure CurrentEnv(Var Env : EnvRec);
  43.   {-Return current environment Record}
  44.  
  45. Procedure NewEnv(Var Env : EnvRec; Size : Word);
  46.   {-Allocate a new environment on the heap}
  47.  
  48. Procedure DisposeEnv(Var Env : EnvRec);
  49.   {-Deallocate an environment previously allocated on heap}
  50.  
  51. Procedure SetCurrentEnv(Env : EnvRec);
  52.   {-Specify a different environment For the current Program}
  53.  
  54. Procedure CopyEnv(Src, Dest : EnvRec);
  55.   {-Copy contents of Src environment to Dest environment}
  56.  
  57. Function EnvFree(Env : EnvRec) : Word;
  58.   {-Return Bytes free in environment}
  59.  
  60. Function GetEnvStr(Env : EnvRec; Search : String) : String;
  61.   {-Return a String from the environment}
  62.  
  63. Function SetEnvStr(Env : EnvRec; Search, Value : String) : Boolean;
  64.   {-Set environment String, returning True if successful}
  65.  
  66. Procedure DumpEnv(Env : EnvRec);
  67.   {-Dump the environment to StdOut}
  68.  
  69. Function ProgramStr : String;
  70.   {-Return the complete path to the current Program, '' if Dos < 3.0}
  71.  
  72. Function SetProgramStr(Env : EnvRec; Path : String) : Boolean;
  73.   {-Add a Program name to the end of an environment if sufficient space}
  74.  
  75.   {$IFDEF UseTpro}
  76. Function ShellWithPrompt(Prompt : String) : Integer;
  77.   {-Shell to Dos With a new prompt}
  78.   {$endIF}
  79.  
  80. Procedure DisposeEnv(Var Env : EnvRec);
  81.   {-Deallocate an environment previously allocated on heap}
  82. begin
  83.   With Env do
  84.     if EnvPtr <> nil then begin
  85.       FreeMem(EnvPtr, EnvLen+31);
  86.       ClearEnvRec(Env);
  87.     end;
  88. end;
  89.  
  90. Procedure SetCurrentEnv(Env : EnvRec);
  91.   {-Specify a different environment For the current Program}
  92. begin
  93.   With Env do
  94.     if EnvSeg <> 0 then
  95.       MemW[PrefixSeg:$2C] := EnvSeg;
  96. end;
  97.  
  98. Procedure CopyEnv(Src, Dest : EnvRec);
  99.   {-Copy contents of Src environment to Dest environment}
  100. Var
  101.   Size : Word;
  102.   SPtr : EnvArrayPtr;
  103.   DPtr : EnvArrayPtr;
  104. begin
  105.   if (Src.EnvSeg = 0) or (Dest.EnvSeg = 0) then
  106.     Exit;
  107.  
  108.   if Src.EnvLen <= Dest.EnvLen then
  109.     {Space For the whole thing}
  110.     Size := Src.EnvLen
  111.   else
  112.     {Take what fits}
  113.     Size := Dest.EnvLen-1;
  114.  
  115.   SPtr := Ptr(Src.EnvSeg, 0);
  116.   DPtr := Ptr(Dest.EnvSeg, 0);
  117.   Move(SPtr^, DPtr^, Size);
  118.   FillChar(DPtr^[Size], Dest.EnvLen-Size, 0);
  119. end;
  120.  
  121. Procedure SkipAsciiZ(EPtr : EnvArrayPtr; Var EOfs : Word);
  122.   {-Skip to end of current AsciiZ String}
  123. begin
  124.   While EPtr^[EOfs] <> #0 do
  125.     Inc(EOfs);
  126. end;
  127.  
  128. Function EnvNext(EPtr : EnvArrayPtr) : Word;
  129.   {-Return the next available location in environment at EPtr^}
  130. Var
  131.   EOfs : Word;
  132. begin
  133.   EOfs := 0;
  134.   if EPtr <> nil then begin
  135.     While EPtr^[EOfs] <> #0 do begin
  136.       SkipAsciiZ(EPtr, EOfs);
  137.       Inc(EOfs);
  138.     end;
  139.   end;
  140.   EnvNext := EOfs;
  141. end;
  142.  
  143. Function EnvFree(Env : EnvRec) : Word;
  144.   {-Return Bytes free in environment}
  145. begin
  146.   With Env do
  147.     if EnvSeg <> 0 then
  148.       EnvFree := EnvLen-EnvNext(Ptr(EnvSeg, 0))-1
  149.     else
  150.       EnvFree := 0;
  151. end;
  152.  
  153. {$IFNDEF UseTpro}
  154. Function StUpcase(S : String) : String;
  155.   {-Uppercase a String}
  156. Var
  157.   SLen : Byte Absolute S;
  158.   I : Integer;
  159. begin
  160.   For I := 1 to SLen do
  161.     S[I] := UpCase(S[I]);
  162.   StUpcase := S;
  163. end;
  164. Function SearchEnv(EPtr : EnvArrayPtr;
  165.                    Var Search : String) : Word;
  166.   {-Return the position of Search in environment, or $FFFF if not found.
  167.     Prior to calling SearchEnv, assure that
  168.       EPtr is not nil,
  169.       Search is not empty
  170.   }
  171. Var
  172.   SLen : Byte Absolute Search;
  173.   EOfs : Word;
  174.   MOfs : Word;
  175.   SOfs : Word;
  176.   Match : Boolean;
  177. begin
  178.   {Force upper Case search}
  179.   Search := Upper(Search);
  180.  
  181.   {Assure search String ends in =}
  182.   if Search[SLen] <> '=' then begin
  183.     Inc(SLen);
  184.     Search[SLen] := '=';
  185.   end;
  186.  
  187.   EOfs := 0;
  188.   While EPtr^[EOfs] <> #0 do begin
  189.     {At the start of a new environment element}
  190.     SOfs := 1;
  191.     MOfs := EOfs;
  192.     Repeat
  193.       Match := (EPtr^[EOfs] = Search[SOfs]);
  194.       if Match then begin
  195.         Inc(EOfs);
  196.         Inc(SOfs);
  197.       end;
  198.     Until not Match or (SOfs > SLen);
  199.  
  200.     if Match then begin
  201.       {Found a match, return index of start of match}
  202.       SearchEnv := MOfs;
  203.       Exit;
  204.     end;
  205.  
  206.     {Skip to end of this environment String}
  207.     SkipAsciiZ(EPtr, EOfs);
  208.  
  209.     {Skip to start of next environment String}
  210.     Inc(EOfs);
  211.   end;
  212.  
  213.   {No match}
  214.   SearchEnv := $FFFF;
  215. end;
  216.  
  217. Procedure GetAsciiZ(EPtr : EnvArrayPtr; Var EOfs : Word; Var EStr : String);
  218.   {-Collect AsciiZ String starting at EPtr^[EOfs]}
  219. Var
  220.   ELen : Byte Absolute EStr;
  221. begin
  222.   ELen := 0;
  223.   While (EPtr^[EOfs] <> #0) and (ELen < 255) do begin
  224.     Inc(ELen);
  225.     EStr[ELen] := EPtr^[EOfs];
  226.     Inc(EOfs);
  227.   end;
  228. end;
  229.  
  230. Function GetEnvStr(Env : EnvRec; Search : String) : String;
  231.   {-Return a String from the environment}
  232. Var
  233.   SLen : Byte Absolute Search;
  234.   EPtr : EnvArrayPtr;
  235.   EOfs : Word;
  236.   EStr : String;
  237.   ELen : Byte Absolute EStr;
  238. begin
  239.   With Env do begin
  240.     ELen := 0;
  241.     if (EnvSeg <> 0) and (SLen <> 0) then begin
  242.       {Find the search String}
  243.       EPtr := Ptr(EnvSeg, 0);
  244.       EOfs := SearchEnv(EPtr, Search);
  245.       if EOfs <> $FFFF then begin
  246.         {Skip over the search String}
  247.         Inc(EOfs, SLen);
  248.         {Build the result String}
  249.         GetAsciiZ(EPtr, EOfs, EStr);
  250.       end;
  251.     end;
  252.     GetEnvStr := EStr;
  253.   end;
  254. end;
  255.  
  256. Implementation
  257.  
  258. Type
  259. SO =
  260.   Record
  261.     O : Word;
  262.     S : Word;
  263.   end;
  264.  
  265. Procedure ClearEnvRec(Var Env : EnvRec);
  266.   {-Initialize an environment Record}
  267. begin
  268.   FillChar(Env, SizeOf(Env), 0);
  269. end;
  270.  
  271. Procedure MasterEnv(Var Env : EnvRec);
  272.   {-Return master environment Record}
  273. Var
  274.   Owner : Word;
  275.   Mcb : Word;
  276.   Eseg : Word;
  277.   Done : Boolean;
  278. begin
  279.   With Env do begin
  280.     ClearEnvRec(Env);
  281.  
  282.     {Interrupt $2E points into COMMAND.COM}
  283.     Owner := MemW[0:(2+4*$2E)];
  284.  
  285.     {Mcb points to memory control block For COMMAND}
  286.     Mcb := Owner-1;
  287.     if (Mem[Mcb:0] <> Byte('M')) or (MemW[Mcb:1] <> Owner) then
  288.       Exit;
  289.  
  290.     {Read segment of environment from PSP of COMMAND}
  291.     Eseg := MemW[Owner:$2C];
  292.  
  293.     {Earlier versions of Dos don't store environment segment there}
  294.     if Eseg = 0 then begin
  295.       {Master environment is next block past COMMAND}
  296.       Mcb := Owner+MemW[Mcb:3];
  297.       if (Mem[Mcb:0] <> Byte('M')) or (MemW[Mcb:1] <> Owner) then
  298.         {Not the right memory control block}
  299.         Exit;
  300.       Eseg := Mcb+1;
  301.     end else
  302.       Mcb := Eseg-1;
  303.  
  304.     {Return segment and length of environment}
  305.     EnvSeg := Eseg;
  306.     EnvLen := MemW[Mcb:3] shl 4;
  307.   end;
  308. end;
  309.  
  310. Procedure CurrentEnv(Var Env : EnvRec);
  311.   {-Return current environment Record}
  312. Var
  313.   ESeg : Word;
  314.   Mcb : Word;
  315. begin
  316.   With Env do begin
  317.     ClearEnvRec(Env);
  318.     ESeg := MemW[PrefixSeg:$2C];
  319.     Mcb := ESeg-1;
  320.     if (Mem[Mcb:0] <> Byte('M')) or (MemW[Mcb:1] <> PrefixSeg) then
  321.       Exit;
  322.     EnvSeg := ESeg;
  323.     EnvLen := MemW[Mcb:3] shl 4;
  324.   end;
  325. end;
  326.  
  327. Procedure NewEnv(Var Env : EnvRec; Size : Word);
  328.   {-Allocate a new environment (on the heap)}
  329. Var
  330.   Mcb : Word;
  331. begin
  332.   With Env do
  333.     if MaxAvail < Size+31 then
  334.       {Insufficient space}
  335.       ClearEnvRec(Env)
  336.     else begin
  337.       {31 extra Bytes For paraGraph alignment, fake MCB}
  338.       GetMem(EnvPtr, Size+31);
  339.       EnvSeg := SO(EnvPtr).S+1;
  340.       if SO(EnvPtr).O <> 0 then
  341.         Inc(EnvSeg);
  342.       EnvLen := Size;
  343.       {Fill it With nulls}
  344.       FillChar(EnvPtr^, Size+31, 0);
  345.       {Make a fake MCB below it}
  346.       Mcb := EnvSeg-1;
  347.       Mem[Mcb:0] := Byte('M');
  348.       MemW[Mcb:1] := PrefixSeg;
  349.       MemW[Mcb:3] := (Size+15) shr 4;
  350.     end;
  351. end;
  352.  
  353. Function SetEnvStr(Env : EnvRec; Search, Value : String) : Boolean;
  354.   {-Set environment String, returning True if successful}
  355. Var
  356.   SLen : Byte Absolute Search;
  357.   VLen : Byte Absolute Value;
  358.   EPtr : EnvArrayPtr;
  359.   ENext : Word;
  360.   EOfs : Word;
  361.   MOfs : Word;
  362.   OldLen : Word;
  363.   NewLen : Word;
  364.   NulLen : Word;
  365. begin
  366.   With Env do begin
  367.     SetEnvStr := False;
  368.     if (EnvSeg = 0) or (SLen = 0) then
  369.       Exit;
  370.     EPtr := Ptr(EnvSeg, 0);
  371.  
  372.     {Find the search String}
  373.     EOfs := SearchEnv(EPtr, Search);
  374.  
  375.     {Get the index of the next available environment location}
  376.     ENext := EnvNext(EPtr);
  377.  
  378.     {Get total length of new environment String}
  379.     NewLen := SLen+VLen;
  380.  
  381.     if EOfs <> $FFFF then begin
  382.       {Search String exists}
  383.       MOfs := EOfs+SLen;
  384.       {Scan to end of String}
  385.       SkipAsciiZ(EPtr, MOfs);
  386.       OldLen := MOfs-EOfs;
  387.       {No extra nulls to add}
  388.       NulLen := 0;
  389.     end else begin
  390.       OldLen := 0;
  391.       {One extra null to add}
  392.       NulLen := 1;
  393.     end;
  394.  
  395.     if VLen <> 0 then
  396.       {Not a pure deletion}
  397.       if ENext+NewLen+NulLen >= EnvLen+OldLen then
  398.         {New String won't fit}
  399.         Exit;
  400.  
  401.     if OldLen <> 0 then begin
  402.       {OverWrite previous environment String}
  403.       Move(EPtr^[MOfs+1], EPtr^[EOfs], ENext-MOfs-1);
  404.       {More space free now}
  405.       Dec(ENext, OldLen+1);
  406.     end;
  407.  
  408.     {Append new String}
  409.     if VLen <> 0 then begin
  410.       Move(Search[1], EPtr^[ENext], SLen);
  411.       Inc(ENext, SLen);
  412.       Move(Value[1], EPtr^[ENext], VLen);
  413.       Inc(ENext, VLen);
  414.     end;
  415.  
  416.     {Clear out the rest of the environment}
  417.     FillChar(EPtr^[ENext], EnvLen-ENext, 0);
  418.  
  419.     SetEnvStr := True;
  420.   end;
  421. end;
  422.  
  423. Procedure DumpEnv(Env : EnvRec);
  424.   {-Dump the environment to StdOut}
  425. Var
  426.   EOfs : Word;
  427.   EPtr : EnvArrayPtr;
  428. begin
  429.   With Env do begin
  430.     if EnvSeg = 0 then
  431.       Exit;
  432.     EPtr := Ptr(EnvSeg, 0);
  433.     EOfs := 0;
  434.     WriteLn;
  435.     While EPtr^[EOfs] <> #0 do begin
  436.       While EPtr^[EOfs] <> #0 do begin
  437.         Write(EPtr^[EOfs]);
  438.         Inc(EOfs);
  439.       end;
  440.       WriteLn;
  441.       Inc(EOfs);
  442.     end;
  443.     WriteLn('Bytes free: ', EnvFree(Env));
  444.   end;
  445. end;
  446. {$IFDEF UseTpro}
  447. Function ShellWithPrompt(Prompt : String) : Integer;
  448.   {-Shell to Dos With a new prompt}
  449. Const
  450.   PromptStr : String[7] = 'PROMPT=';
  451. Var
  452.   PLen : Byte Absolute Prompt;
  453.   NSize : Word;
  454.   Status : Integer;
  455.   CE : EnvRec;
  456.   NE : EnvRec;
  457.   OldP : String;
  458.   OldPLen : Byte Absolute OldP;
  459. begin
  460.   {Point to current environment}
  461.   CurrentEnv(CE);
  462.   if CE.EnvSeg = 0 then begin
  463.     {Error getting environment}
  464.     ShellWithPrompt := -5;
  465.     Exit;
  466.   end;
  467.  
  468.   {Compute size of new environment}
  469.   OldP := GetEnvStr(CE, PromptStr);
  470.   NSize := CE.EnvLen;
  471.   if OldPLen < PLen then
  472.     Inc(NSize, PLen-OldPLen);
  473.  
  474.   {Allocate and initialize a new environment}
  475.   NewEnv(NE, NSize);
  476.   if NE.EnvSeg = 0 then begin
  477.     {Insufficient memory For new environment}
  478.     ShellWithPrompt := -6;
  479.     Exit;
  480.   end;
  481.   CopyEnv(CE, NE);
  482.  
  483.   {Get the Program name from the current environment}
  484.   OldP := ProgramStr;
  485.  
  486.   {Set the new prompt String}
  487.   if not SetEnvStr(NE, PromptStr, Prompt) then begin
  488.     {Program error, should have enough space}
  489.     ShellWithPrompt := -7;
  490.     Exit;
  491.   end;
  492.  
  493.   {Transfer Program name to new environment if possible}
  494.   if not SetProgramStr(NE, OldP) then
  495.     ;
  496.  
  497.   {Point to new environment}
  498.   SetCurrentEnv(NE);
  499.  
  500.   {Shell to Dos With new prompt in place}
  501.   {Status := Exec('', True, ShellUserProc);}
  502.  
  503.   {Restore previous environment}
  504.   SetCurrentEnv(CE);
  505.  
  506.   {Release the heap space}
  507.   if Status >= 0 then
  508.     DisposeEnv(NE);
  509.  
  510.   {Return exec status}
  511.   ShellWithPrompt := Status;
  512. end;
  513. {$endIF}
  514.  
  515. end.
  516.  
  517. { EXAMPLE PROGRAM }
  518.  
  519. Function DosVersion : Word;
  520.   {-Return the Dos version, major part in AX}
  521. Inline(
  522.   $B4/$30/                 {mov ah,$30}
  523.   $CD/$21/                 {int $21}
  524.   $86/$C4);                {xchg ah,al}
  525.  
  526. Function ProgramStr : String;
  527.   {-Return the name of the current Program, '' if Dos < 3.0}
  528. Var
  529.   EOfs : Word;
  530.   Env : EnvRec;
  531.   EPtr : EnvArrayPtr;
  532.   PStr : String;
  533. begin
  534.   ProgramStr := '';
  535.   if DosVersion < $0300 then
  536.     Exit;
  537.   CurrentEnv(Env);
  538.   if Env.EnvSeg = 0 then
  539.     Exit;
  540.   {Find the end of the current environment}
  541.   EPtr := Ptr(Env.EnvSeg, 0);
  542.   EOfs := EnvNext(EPtr);
  543.   {Skip to start of path name}
  544.   Inc(EOfs, 3);
  545.   {Collect the path name}
  546.   GetAsciiZ(EPtr, EOfs, PStr);
  547.   ProgramStr := PStr;
  548. end;
  549.  
  550. Function SetProgramStr(Env : EnvRec; Path : String) : Boolean;
  551.   {-Add a Program name to the end of an environment if sufficient space}
  552. Var
  553.   PLen : Byte Absolute Path;
  554.   EOfs : Word;
  555.   Numb : Word;
  556.   EPtr : EnvArrayPtr;
  557. begin
  558.   SetProgramStr := False;
  559.   With Env do begin
  560.     if EnvSeg = 0 then
  561.       Exit;
  562.     {Find the end of the current environment}
  563.     EPtr := Ptr(EnvSeg, 0);
  564.     EOfs := EnvNext(EPtr);
  565.     {Assure space For path}
  566.     if EnvLen < PLen+EOfs+4 then
  567.       Exit;
  568.     {Put in the count field}
  569.     Inc(EOfs);
  570.     Numb := 1;
  571.     Move(Numb, EPtr^[EOfs], 2);
  572.     {Skip to start of path name}
  573.     Inc(EOfs, 2);
  574.     {Move the path into place}
  575.     Path := Upper(Path);
  576.     Move(Path[1], EPtr^[EOfs], PLen);
  577.     {Null terminate}
  578.     Inc(EOfs, PLen);
  579.     EPtr^[EOfs] := #0;
  580.     SetProgramStr := True;
  581.   end;
  582. end;
  583.